package service_sys

import (
	"context"
	"encoding/json"
	"go_web/internal/global"
	"go_web/internal/model/model_sys"
	"go_web/internal/repo/repo_sys"
	"go_web/internal/req/req_sys"
	"go_web/internal/res/res_sys"
	"go_web/pkg/req"
	"go_web/pkg/res"
	"go_web/pkg/utils"
	"math"

	"github.com/fatih/structs"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/copier"
	"gorm.io/gen"
	"gorm.io/gen/field"
)

type SysDataScopeService struct{}

// 创建新的 SysDataScopeService
func NewSysDataScopeService() *SysDataScopeService {
	return &SysDataScopeService{}
}

// 分页查询
func (*SysDataScopeService) Page(c context.Context, pageReq req_sys.SysDataScopePageReq) (*res.PageRes, error) {
	offset := (pageReq.Page - 1) * pageReq.PageSize
	q := repo_sys.SysDataScope.WithContext(c)

	// 排序处理
	if pageReq.SortField != nil {
		sortField := utils.ConvertToSnakeCase(*pageReq.SortField)
		orderFieldExpr := field.NewUnsafeFieldRaw(sortField)
		if pageReq.SortOrder != nil {
			if *pageReq.SortOrder == "asc" {
				q = q.Order(orderFieldExpr.Asc())
			} else {
				q = q.Order(orderFieldExpr.Desc())
			}
		} else {
			q = q.Order(orderFieldExpr.Asc())
		}
	}

	// 执行分页查询
	list, count, err := q.FindByPage(offset, pageReq.PageSize)
	if err != nil {
		return nil, err
	}

	// 计算总页数
	page := res.PageRes{
		List:     list,
		Total:    count,
		Page:     pageReq.Page,
		PageSize: pageReq.PageSize,
		Pages:    int64(math.Ceil(float64(count) / float64(pageReq.PageSize))),
	}

	return &page, nil
}

// 添加 SysDataScope 已开启事务
func (*SysDataScopeService) Add(c context.Context, addReq req_sys.SysDataScopeAddReq) (int64, error) {
	var SysDataScope model_sys.SysDataScope
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.SysDataScope.WithContext(c)
		err := copier.Copy(&SysDataScope, &addReq)
		if err != nil {
			return err
		}
		err = q.Create(&SysDataScope)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return 0, err
	}
	return SysDataScope.ID, nil
}

// 编辑 SysDataScope 已开启事务
func (*SysDataScopeService) Edit(c context.Context, editReq req_sys.SysDataScopeEditReq) (int64, error) {
	var result gen.ResultInfo
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.SysDataScope.WithContext(c).Where(repo_sys.SysDataScope.ID.Eq(editReq.ID))
		SysDataScope, err := q.First()
		if err != nil {
			return err
		}
		err = copier.Copy(&SysDataScope, &editReq)
		if err != nil {
			return err
		}
		result, err = q.Updates(structs.Map(SysDataScope))
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		if utils.IsOptimisticLockError(err) {
			return -1, nil // 乐观锁报错（版本不一致）
		}
		return 0, err
	}
	return result.RowsAffected, nil
}

// 删除 SysDataScope 已开启事务
func (*SysDataScopeService) Delete(c context.Context, idsReq req.IdsReq) (int64, error) {
	var result gen.ResultInfo
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := repo_sys.SysDataScope.WithContext(c)
		ids, err := idsReq.ToInt64Slice()
		if err != nil {
			return err
		}
		sysUserList, err := q.Where(repo_sys.SysUser.ID.In(ids...)).Find()
		if err != nil {
			return err
		}
		result, err = q.Delete(sysUserList...)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return 0, err
	}
	return result.RowsAffected, nil
}

// 查看 SysDataScope 详情
func (*SysDataScopeService) Detail(c context.Context, userId int64) (*model_sys.SysDataScope, error) {
	q := repo_sys.SysDataScope.WithContext(c)
	SysDataScope, err := q.Where(repo_sys.SysDataScope.ID.Eq(userId)).First()
	if err != nil {
		return nil, err
	}
	return SysDataScope, nil
}

func (*SysDataScopeService) ResetToRole(c context.Context, scopeStr string) (string, error) {
	reqUrlList := global.ReqUrls
	roleList, err := repo_sys.SysDictDatum.Where(repo_sys.SysDictDatum.DictType.
		Eq("ROLE")).Find()
	if err != nil {
		return "", err
	}
	var sysDataScopeList []*model_sys.SysDataScope
	for _, role := range roleList {
		for _, reqUrl := range reqUrlList {
			sysDataScope := &model_sys.SysDataScope{
				Role:       role.DictCode,
				ScopeType:  scopeStr,
				TargetType: "ROLE",
				ReqUrl:     reqUrl,
			}
			sysDataScopeList = append(sysDataScopeList, sysDataScope)
		}
	}
	repo_sys.SysDataScope.WithContext(c).Where(repo_sys.SysDataScope.TargetType.Eq("ROLE")).Unscoped().Delete()
	err = repo_sys.SysDataScope.WithContext(c).Save(sysDataScopeList...)
	if err != nil {
		return "", err
	}
	return "设置成功", nil
}

func (s *SysDataScopeService) UserList(c *gin.Context, userId int64) ([]*res_sys.SysDataScopeRes, error) {
	// 获取权限 URL 列表
	permissionUrlList := global.ReqUrls

	// 查询用户数据范围列表
	var sysDataScopeList []*model_sys.SysDataScope
	sysDataScopeList, err := repo_sys.SysDataScope.Where(repo_sys.SysDataScope.TargetType.Eq("USER")).
		Where(repo_sys.SysDataScope.TargetID.Eq(userId)).Find()
	if err != nil {
		return nil, err
	}

	// 创建映射，方便查找
	sysDataScopeMap := make(map[string]*model_sys.SysDataScope)
	for _, dataScope := range sysDataScopeList {
		sysDataScopeMap[dataScope.ReqUrl] = dataScope
	}

	// 创建 SysDataScopeVO 列表
	var sysDataScopeResList []*res_sys.SysDataScopeRes
	for _, reqUrl := range permissionUrlList {
		sysDataScopeRes := &res_sys.SysDataScopeRes{
			ReqUrl:    reqUrl,
			Status:    false, // 默认不启用权限检查
			IsAccess:  true,
			ScopeType: "ALL",
		}

		if sysDataScope, exists := sysDataScopeMap[reqUrl]; exists {
			sysDataScopeRes.ScopeType = sysDataScope.ScopeType
			sysDataScopeRes.IsAccess = sysDataScope.IsAccess
			jsonBytes, err := sysDataScope.CustomOrgJson.MarshalJSON()
			if err != nil {
				return nil, err
			}
			json.Unmarshal(jsonBytes, &sysDataScopeRes.CustomOrgJson)
			sysDataScopeRes.Status = true // 启用权限检查
		}

		sysDataScopeResList = append(sysDataScopeResList, sysDataScopeRes)
	}

	return sysDataScopeResList, nil
}

func (s *SysDataScopeService) RoleList(c *gin.Context, role string) ([]*res_sys.SysDataScopeRes, error) {
	// 获取权限 URL 列表
	permissionUrlList := global.ReqUrls

	// 查询角色数据范围列表
	var sysDataScopeList []*model_sys.SysDataScope
	sysDataScopeList, err := repo_sys.SysDataScope.Where(repo_sys.SysDataScope.TargetType.Eq("ROLE")).
		Where(repo_sys.SysDataScope.Role.Eq(role)).Find()
	if err != nil {
		return nil, err
	}

	// 创建映射，方便查找
	sysDataScopeMap := make(map[string]*model_sys.SysDataScope)
	for _, dataScope := range sysDataScopeList {
		sysDataScopeMap[dataScope.ReqUrl] = dataScope
	}

	// 创建 SysDataScopeVO 列表
	var sysDataScopeResList []*res_sys.SysDataScopeRes
	for _, reqUrl := range permissionUrlList {
		sysDataScopeRes := &res_sys.SysDataScopeRes{
			ReqUrl:    reqUrl,
			Status:    false, // 默认不启用权限检查
			IsAccess:  true,
			ScopeType: "ALL",
		}

		if sysDataScope, exists := sysDataScopeMap[reqUrl]; exists {
			sysDataScopeRes.ScopeType = sysDataScope.ScopeType
			sysDataScopeRes.IsAccess = sysDataScope.IsAccess
			sysDataScopeRes.CustomOrgJson = sysDataScope.CustomOrgJson

			sysDataScopeRes.Status = true // 启用权限检查
		}

		sysDataScopeResList = append(sysDataScopeResList, sysDataScopeRes)
	}

	return sysDataScopeResList, nil
}

func (s *SysDataScopeService) RoleSaveList(c *gin.Context, sysDataScopeRoleReq req_sys.SysDataScopeRoleReq) (int64, error) {
	_, err := repo_sys.SysDataScope.WithContext(c).Where(repo_sys.SysDataScope.TargetType.Eq("ROLE")).
		Where(repo_sys.SysDataScope.Role.Eq(sysDataScopeRoleReq.Role)).Unscoped().Delete()
	if err != nil {
		return 0, err
	}
	var sysDataScopeList []*model_sys.SysDataScope
	for _, sysDataScopeRes := range sysDataScopeRoleReq.SysDataScopeResList {
		if sysDataScopeRes.Status {
			sysDataScope := &model_sys.SysDataScope{
				Role:          sysDataScopeRoleReq.Role,
				ScopeType:     sysDataScopeRes.ScopeType,
				TargetType:    "ROLE",
				ReqUrl:        sysDataScopeRes.ReqUrl,
				IsAccess:      sysDataScopeRes.IsAccess,
				CustomOrgJson: sysDataScopeRes.CustomOrgJson,
			}
			sysDataScopeList = append(sysDataScopeList, sysDataScope)
		}
	}
	err = repo_sys.SysDataScope.WithContext(c).Save(sysDataScopeList...)
	if err != nil {
		return 0, err
	}
	return int64(len(sysDataScopeList)), nil
}

func (s *SysDataScopeService) UserSaveList(c *gin.Context, sysDataScopeUserReq req_sys.SysDataScopeUserReq) (int64, error) {
	_, err := repo_sys.SysDataScope.WithContext(c).Where(repo_sys.SysDataScope.TargetType.Eq("USER")).
		Where(repo_sys.SysDataScope.TargetID.Eq(sysDataScopeUserReq.UserId)).Unscoped().Delete()
	if err != nil {
		return 0, err
	}
	var sysDataScopeList []*model_sys.SysDataScope
	for _, sysDataScopeRes := range sysDataScopeUserReq.SysDataScopeResList {
		if sysDataScopeRes.Status {
			sysDataScope := &model_sys.SysDataScope{
				TargetId:      sysDataScopeUserReq.UserId,
				ScopeType:     sysDataScopeRes.ScopeType,
				TargetType:    "USER",
				ReqUrl:        sysDataScopeRes.ReqUrl,
				IsAccess:      sysDataScopeRes.IsAccess,
				CustomOrgJson: sysDataScopeRes.CustomOrgJson,
			}
			sysDataScopeList = append(sysDataScopeList, sysDataScope)
		}
	}
	err = repo_sys.SysDataScope.WithContext(c).Save(sysDataScopeList...)
	if err != nil {
		return 0, err
	}
	return int64(len(sysDataScopeList)), nil
}
